home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / uupc 3.1 / (uupc π) / dcpapkt.c < prev    next >
Encoding:
Text File  |  1992-09-15  |  63.4 KB  |  2,515 lines  |  [TEXT/ALFA]

  1. /*
  2.     dcpapkt.c
  3.     for uupc 3.1
  4.     by Dave Platt (dplatt@snulbug.mtview.ca.us)
  5.     derived from protz.c by Doug Evans
  6. */
  7.  
  8. /* protz.c        Version 1.5, 92Apr24 */
  9.  
  10. /*
  11.  * Doug Evans, dje@sspiff.UUCP or dje@ersys.edmonton.ab.ca
  12.  *
  13.  * This file provides the Zmodem protocol (by Chuck Forsberg) for
  14.  * Ian Taylor's UUCP package.
  15.  *
  16.  * It was originally developed to establish a uucp link between myself and my
  17.  * employer: Ivation Datasystems, Inc. of Ottawa. 
  18.  *
  19.  * My thanks to Ivation for letting me release this to the public. Given that
  20.  * Zmodem is in the public domain, no additional copyrights have been added.
  21.  *
  22.  *****************************************************************************
  23.  *
  24.  * It's been difficult fitting Zmodem into the UUCP world. I have been guided
  25.  * mostly by trying to plug it into Taylor UUCP. Where "the Zmodem way of doing
  26.  * things" conflicted with "the UUCP way of doing things", I have err'd on the
  27.  * side of UUCP. At the end of it all, I have achieved something that will plug
  28.  * into Taylor UUCP very easily, but some might argue that I have corrupted Z
  29.  * too much. At any rate, compatibility with sz/rz was sacrificed to achieve a
  30.  * clean UUCP protocol. Given that, I took the opportunity to start from
  31.  * scratch when defining protocol constants (EG: ZBIN).
  32.  *
  33.  * 1) I wasn't quite sure how to enhance Zmodem to handle send+receive in one
  34.  *    session, so I added a 'g' protocol like initialization sequence. This
  35.  *    also gets this stuff out of the way, in case we ever try to support
  36.  *    full-duplex.
  37.  *
  38.  *    Caller                Callee
  39.  *    ------                ------
  40.  *    ZINIT        -->    <-- ZINIT
  41.  *    ZDATA (ZCRCF)    -->    <-- ZDATA (ZCRCF)
  42.  *    ZACK        -->    <-- ZACK
  43.  *    ZINITEND    -->    <-- ZINITEND
  44.  *
  45.  *    ZINIT is a combination of ZRINIT and ZSINIT and is intended to exchange
  46.  *    simple protocol information (flags) and the protocol version number.
  47.  *    ZDATA is intended to include window size information as well as the
  48.  *    "Myattn" string (although at the moment it doesn't contain anything).
  49.  *    ZDATA may contain at most 1k bytes of data and is sent out as one ZCRCF
  50.  *    packet. Two ack's (ZACK + ZINITEND) are needed to ensure both sides have
  51.  *    received ZDATA.
  52.  *
  53.  * 2) I've hardcoded several protocol parameters, like 32 bit CRC's for data.
  54.  *    Others are not supported (we don't need them).
  55.  *
  56.  * 3) ZHEX headers use 32 bit CRC's.
  57.  *
  58.  * 4) Zmodem sends the ZFILE message "in one chunk". If there are errors, the
  59.  *    entire string is resent. I have continued this practice. All UUCP
  60.  *    commands are sent "in one chunk". This can be changed down the road if
  61.  *    necessary.
  62.  *
  63.  * 5) The ZEOF message has been replaced with a new ZCRCx value: ZCRCF. ZCRCF
  64.  *    is identical to ZCRCW except that it indicates the end of the message.
  65.  *    The protocol here is *not* a file transfer protocol. It is an end to end
  66.  *    transport protocol (that preserves message boundaries).
  67.  *
  68.  * 6) Zmodem handles restarting a file transfer, but as best as I can tell UUCP
  69.  *    does not. At least Taylor UUCP doesn't. And if UUCP does start handling
  70.  *    file restart, can it be plugged into the existing Zmodem way with zero
  71.  *    changes? Beats me. Therefore I have removed this part of the code. One
  72.  *    can always put it back in if and when UUCP handles it. Ditto for other
  73.  *    pieces of removed code: there's no point in overly complicating this code
  74.  *    when supporting all the bells and whistles requires enhancements to UUCP
  75.  *    itself.
  76.  *
  77.  *    *** It is easier to put code back in in an upward compatible manner ***
  78.  *    *** than it is to correct for misunderstood code or poorly merged   ***
  79.  *    *** (Zmodem vs UUCP) code.                                          ***
  80.  *
  81.  * 7) For the character in the initial "protocol selection" sequence, I have
  82.  *    chosen 'a'. I'm told 'z' is already in use for something that isn't
  83.  *    Zmodem. It's entirely reasonable to believe that if Zmodem ever becomes a
  84.  *    standard UUCP protocol, this won't be it (so I'll leave z/Z for them).
  85.  *    Publicly, this is the 'a' protocol. Internally, it is refered to as 'z'.
  86.  *    A little confusing, I know. Maybe in time I'll refer to it internally as
  87.  *    'a', or maybe in time this will be *the* 'z' protocol.
  88.  *
  89.  * 8) Since we are writing a transport protocol, which isn't supposed to know
  90.  *    anything about what is being transfered or where it is coming from, the
  91.  *    header data value has changed meaning. It no longer means "file position"
  92.  *    but instead means "window position". It is a running counter of the bytes
  93.  *    transfered. Each "message" begins on a 1k boundary so the count isn't a
  94.  *    precise byte count. The counter wraps every 4 gigabytes, although this
  95.  *    wrapping isn't supported yet.
  96.  *
  97.  *    FIXME: At present the max data transfered per session is 4 gigabytes.
  98.  *
  99.  ****************************************************************************
  100.  *
  101.  * A typical message sequence is (master sending file to slave):
  102.  *
  103.  *      Master                          Slave
  104.  *      ------                          -----
  105.  *    ZDATA (S, ZCRCF)    -->
  106.  *                <--    ZACK
  107.  *                <--    ZDATA (SY, ZCRCF)
  108.  *    ZACK            -->
  109.  *    ZDATA            -->
  110.  *                        ...    <--    ZACK/ZRPOS
  111.  *    ZDATA (ZCRCF)        -->
  112.  *                <--    ZACK
  113.  *                <--    ZDATA (CY, ZCRCF)
  114.  *    ZACK            -->
  115.  *
  116.  * A typical message sequence is (master receiving file from slave):
  117.  *
  118.  *    Master                Slave
  119.  *    ------                -----
  120.  *    ZDATA (R, ZCRCF)    -->
  121.  *                <--    ZACK
  122.  *                <--    ZDATA (RY, ZCRCF)
  123.  *    ZACK            -->
  124.  *                <--    ZDATA
  125.  *    ZACK/ZRPOS    ...    -->
  126.  *                <--    ZDATA (ZCRCF)
  127.  *    ZACK            -->
  128.  *    ZDATA (CY, ZCRCF)    -->
  129.  *                <--    ZACK
  130.  *
  131.  *****************************************************************************
  132.  *
  133.  * Fitting this into Taylor UUCP:
  134.  *
  135.  * The protocol entry in <asProtocols> is:
  136.  *
  137.  *    { 'a', FALSE, RELIABLE_EIGHT,
  138.  *        asZproto_params, fzstart, fzshutdown, fzsendcmd, zzgetspace,
  139.  *        fzsenddata, fzprocess, fzwait, fzfile },
  140.  *
  141.   *****************************************************************************
  142.  *
  143.  * Notes:
  144.  * 1) For future bidirectional concerns, keep packet types "unidirectional".
  145.  *    Sender always uses:    ZDATA, ZNAK
  146.  *    Receiver always uses:    ZRPOS, ZACK
  147.  *    There is no intersection.
  148.  *
  149.  *    I'm not sure if this is necessary or even useful, but it seems to be.
  150.  *
  151.  * 2) I use to store the byte count / 32 in the data header. This left 5 bits
  152.  *    unused for future concerns. I removed this because of the following
  153.  *    situation when sending a file:
  154.  *
  155.  *    ZDATA (ZCRCG, xx bytes) - received ok
  156.  *    ZDATA (ZCRCF, 0 bytes)  - corrupted
  157.  *
  158.  *    At this point the receiver would like to send back a ZRPOS with a value 
  159.  *    of the size of the file. However, it can't because the value is divided
  160.  *    by 32, and it would have to round up to the next multiple of 32. This
  161.  *    seemed a little ugly, so I went with using the entire header to store
  162.  *    the byte count.
  163.  *
  164.  *****************************************************************************
  165.  *
  166.  * Source version:
  167.  * 
  168.  * 1.1,2,3
  169.  *    Protocol version 0
  170.  *    Early attempts, completely rewritten later.
  171.  *
  172.  * 1.4    Protocol version 1
  173.  *    Beta test sent to Ian for analysis 92Apr18.
  174.  *
  175.  * 1.5    Protocol version 1
  176.  *    Released 92Apr24.
  177.  *
  178.  *****************************************************************************
  179.  *
  180.  * Protocol version:
  181.  *
  182.  * A version number is exchanged in the ZINIT message, so it is possible to
  183.  * correct or enhance the protocol, without breaking existing versions.
  184.  * The purpose of this section is to document these versions as they come out.
  185.  * Remember, this is the protocol version, not the source version.
  186.  *
  187.  * 0    Initial version.
  188.  *    Zmodem controlled file transfer. This was more of a "plug Z
  189.  *    into UUCP as is" port.
  190.  *
  191.  * 1    Complete rewrite.
  192.  *    Made Z more of a transport protocol. UUCP now controls transfer and Z
  193.  *    is on the same footing as the other UUCP protocols.
  194.  *    Theoretically, there will be little pain when UUCP goes bidirectional.
  195.  */
  196.  
  197. #ifdef THINK_C
  198.  
  199. #include <stdio.h>
  200. #include <string.h>
  201. #include <time.h>
  202.  
  203. #include "dcp.h"
  204. #include "sio.h"
  205.  
  206. typedef void * pointer;
  207.  
  208. #define eSendfile fp
  209. #define ffileseek(fd, offset, type) (lseek(fd, offset, type) != EOF)
  210. #define xmalloc NewPtr
  211. #define xfree DisposPtr
  212. #define fsend_data(ptr, count, doread) swrite(ptr, count)
  213. #define ffileclearerror(x) /* x */
  214. #define usendfile_error(x) /* x */
  215. #define fgot_data(a,b,c,d,e) (1 /* a b c d e */)
  216.  
  217. #define PKTSIZE   128
  218.  
  219.  
  220. #endif
  221.  
  222. #define ZPROTOCOL_VERSION    1
  223.  
  224. /*
  225.  * Control message characters ...
  226.  */
  227.  
  228. #define ZPAD    '*'    /* Padding character begins frames */
  229. #define ZDLE    030    /* Ctrl-X Zmodem escape - `ala BISYNC DLE */
  230. #define ZBIN    'A'    /* Binary frame indicator */
  231. #define ZHEX    'B'    /* HEX frame indicator */
  232.  
  233. /*
  234.  * Frame types (see array "frametypes" in zm.c) ...
  235.  *
  236.  * Note that the numbers here have been reorganized, as we don't support
  237.  * all of them (nor do we need to).
  238.  *
  239.  * WARNING: The init sequence assumes ZINIT < ZDATA < ZACK < ZINITEND.
  240.  */
  241.  
  242. #define ZINIT        0    /* Init (contains protocol version, flags) */
  243. #define ZDATA        1    /* Data packet(s) follow */
  244. #define ZRPOS        2    /* Resume data trans at this position */
  245. #define ZACK        3    /* ACK to above */
  246. #define ZNAK        4    /* Last packet was garbled */
  247. #define Zreserved    5    /* reserved (for future concerns) */
  248. #define ZINITEND    6    /* end of init sequence */
  249. #define ZFIN        7    /* Finish session */
  250.  
  251. /*
  252.  * ZDLE sequences ...
  253.  *
  254.  * Note addition of ZCRCF: "end of message".
  255.  */
  256.  
  257. #define ZCRCE 'h'    /* CRC next, frame ends, header packet follows */
  258. #define ZCRCG 'i'    /* CRC next, frame continues nonstop */
  259. #define ZCRCQ 'j'    /* CRC next, frame continues, ZACK expected */
  260. #define ZCRCW 'k'    /* CRC next, ZACK expected, end of frame */
  261. #define ZCRCF 'l'    /* CRC next, ZACK expected, end of message */
  262.  
  263. #define ZRUB0 'm'    /* Translate to rubout 0177 */
  264. #define ZRUB1 'n'    /* Translate to rubout 0377 */
  265.  
  266.  
  267. /*
  268.  * zdlread return values (internal) ...
  269.  * Other values are ZM_ERROR, ZM_TIMEOUT, ZM_RCDO.
  270.  */
  271.  
  272. #define GOTOR    0400
  273. #define GOTCRCE (ZCRCE | GOTOR)    /* ZDLE-ZCRCE received */
  274. #define GOTCRCG (ZCRCG | GOTOR)    /* ZDLE-ZCRCG received */
  275. #define GOTCRCQ (ZCRCQ | GOTOR)    /* ZDLE-ZCRCQ received */
  276. #define GOTCRCW (ZCRCW | GOTOR)    /* ZDLE-ZCRCW received */
  277. #define GOTCRCF (ZCRCF | GOTOR)    /* ZDLE-ZCRCF received */
  278.  
  279. /*
  280.  * Byte positions within header array ...
  281.  */
  282.  
  283. #define ZF0    3    /* First flags byte */
  284. #define ZF1    2
  285. #define ZF2    1
  286. #define ZF3    0
  287.  
  288. #define ZP0    0    /* Low order 8 bits of position */
  289. #define ZP1    1
  290. #define ZP2    2
  291. #define ZP3    3    /* High order 8 bits of position */
  292.  
  293. /*
  294.  * Bit Masks for ZRQINIT flags byte ZF0 ...
  295.  */
  296.  
  297. #define TX_ESCCTL    1    /* Tx will escape control chars */
  298.  
  299. /*
  300.  * Possible errors when running ZMODEM ...
  301.  */
  302.  
  303. #define    ZM_ERROR    (-1)    /* crc error, etc. */
  304. #define ZM_TIMEOUT    (-2)
  305. #define ZM_RCDO        (-3)    /* Carrier Lost */
  306.  
  307. /*
  308.  * ASCII characters ...
  309.  */
  310.  
  311. #define LF        012
  312. #define CR        015
  313. #ifndef XON
  314. # define XON        021
  315. #endif
  316. #ifndef XOFF
  317. # define XOFF        023
  318. #endif
  319.  
  320. #define XON_WAIT    10    /* seconds */
  321.  
  322. /*
  323.  * Packet sizes ...
  324.  *
  325.  * FIXME: CPACKETSIZE is hardcoded in a lot of places.
  326.  *    It's not clear to me whether changing it's value would be a
  327.  *    "good thing" or not. But of course that doesn't excuse the hardcoding.
  328.  */
  329.  
  330. #define CPACKETSIZE        1024    /* max packet size (data only) */
  331. #define CFRAMELEN        12    /* header size */
  332. #define CSUFFIXLEN        10    /* suffix at end of data packets */
  333. #define CEXCHANGE_INIT_RETRIES    4
  334.  
  335. /*
  336.  * Data types ...
  337.  */
  338.  
  339. typedef unsigned char achdrval_t[4];
  340. typedef unsigned long hdrval_t;
  341. typedef unsigned long winpos_t;
  342.  
  343. /*
  344.  * Configurable parms ...
  345.  *
  346.  * FIXME: <cZrx_buf_len> isn't used yet. It may not be needed.
  347.  */
  348.  
  349. #define CTIMEOUT        10
  350. #define CRETRIES        10
  351. #define CSTARTUP_RETRIES    4
  352. #define CGARBAGE        2400
  353. #define CSEND_WINDOW        16384
  354. #define FESCAPE_CONTROL        FALSE
  355.  
  356. static int cZtimeout = CTIMEOUT;    /* (seconds) */
  357. static int cZretries = CRETRIES;
  358. static int cZstartup_retries = CSTARTUP_RETRIES;
  359. static int cZmax_garbage = CGARBAGE;        /* max garbage before header */
  360. static int cZtx_window = CSEND_WINDOW;        /* our transmission window */
  361. static int cZrx_buf_len = 0;            /* our receiver's buffer size */
  362. static boolean fZesc_ctl = FESCAPE_CONTROL;    /* escape control chars */
  363.  
  364. #ifndef    THINK_C
  365.  
  366. struct scmdtab asZproto_params[] =
  367. {
  368.     {"timeout", CMDTABTYPE_INT, (pointer) & cZtimeout, NULL},
  369.     {"retries", CMDTABTYPE_INT, (pointer) & cZretries, NULL},
  370.     {"startup-retries", CMDTABTYPE_INT, (pointer) & cZstartup_retries, NULL},
  371.     {"garbage", CMDTABTYPE_INT, (pointer) & cZmax_garbage, NULL},
  372.     {"send-window", CMDTABTYPE_INT, (pointer) & cZtx_window, NULL},
  373.     {"escape-control", CMDTABTYPE_BOOLEAN, (pointer) & fZesc_ctl, NULL},
  374.     {NULL, 0, NULL, NULL}
  375. };
  376.  
  377. #endif
  378.  
  379. /*
  380.  * Variables for statistic gathering ...
  381.  *
  382.  * We use <wpZtxpos, wpZrxbytes> to record the number of "packets"
  383.  * sent/received. Packets is in double quotes because some of them aren't full.
  384.  */
  385.  
  386. static unsigned long cZheaders_sent;
  387. static unsigned long cZheaders_received;
  388. static unsigned long cZbytes_resent;
  389. static unsigned long cZtimeouts;
  390. static unsigned long cZerrors;
  391.  
  392. /*
  393.  * Data buffers ...
  394.  */
  395.  
  396. static char *zZtx_buf;        /* transmit buffer */
  397.  
  398. static char *zZtx_packet_buf;    /* raw outgoing packet data */
  399. static char *zZrx_packet_buf;    /* raw incoming packet data */
  400.  
  401. /*
  402.  * Transmitter state variables ...
  403.  */
  404.  
  405. static unsigned cZblklen;    /* data length in sent/received packets */
  406. static unsigned cZtxwspac;    /* spacing between ZCRCQ requests */
  407. /*static unsigned cZblklen_override;*//* override value for <cZblklen> */
  408. static unsigned cZtxwcnt;    /* counter used to space ack requests */
  409. static unsigned cZrxwcnt;    /* counter used to watch receiver's buf size */
  410. static winpos_t wpZtxstart;    /* <wpZtxpos> when message started */
  411. static winpos_t wpZtxpos;    /* transmitter position */
  412. static winpos_t wpZlastsync;    /* last offset to which we got a ZRPOS */
  413. static winpos_t wpZlrxpos;    /* receiver's last reported offset */
  414. static winpos_t wpZrxpos;    /* receiver file position */
  415.  
  416. static int iZlast_tx_data_packet; /* type of last ZDATA packet (ZCRCx) */
  417. static int iZjunk_count;    /* amount of garbage characters received */
  418. static int iZtleft;        /* for dynamic packet resizing */
  419.  
  420. static int iZbeenhereb4;    /* times we've been ZRPOS'd to same place */
  421.  
  422. /*
  423.  * Receiver state variables ...
  424.  */
  425.  
  426. static winpos_t wpZrxbytes;    /* receiver byte count */
  427. static int iZlast_rx_data_packet; /* last successfully received ZCRCx packet */
  428.  
  429. /*
  430.  * Misc. globals ...
  431.  */
  432.  
  433. static char xon = XON;
  434.  
  435. #ifdef DJE_TESTING
  436. int uucptest = -1;
  437. int uucptest2;
  438. int uucptestseed;
  439. #endif
  440.  
  441. /*
  442.  * Kludge!!!
  443.  * See fzfinish_tx(). Basically the next two globals are used to record the
  444.  * fact that we got a ZDATA, but aren't quite ready to process it.
  445.  */
  446.  
  447. static int iZpkt_rcvd_kludge;            /* -1 if not valid */
  448. static hdrval_t hvZpkt_hdrval_kludge;
  449.  
  450. /*
  451.  * Packet types ...
  452.  */
  453.  
  454. static const char *azZframe_types[] = {
  455.     "Carrier Lost",        /* -3 */
  456.     "Timeout",        /* -2 */
  457.     "Error",        /* -1 */
  458. #define FTOFFSET 3
  459.     "ZINIT",
  460.     "ZDATA",
  461.     "ZRPOS",
  462.     "ZACK",
  463.     "ZNAK",
  464.     "Zreserved",
  465.     "ZINITEND",
  466.     "ZFIN",
  467.     "UNKNOWN!!!"
  468. };
  469. #define FTNUMBER    (sizeof(azZframe_types) / sizeof(char *))
  470.  
  471. #ifndef min
  472. #define min(a, b)    ((a) < (b) ? (a) : (b))
  473. #endif
  474. #define ZZHEADER_NAME(itype) \
  475.         azZframe_types[min((itype) + FTOFFSET, FTNUMBER - 1)]
  476.  
  477. /*
  478.  * Local functions ...
  479.  */
  480.  
  481. #ifdef THINK_C
  482. # define P(x) x
  483. #endif
  484.  
  485. boolean fzstart P((boolean fmaster));
  486. boolean fzshutdown P((void));
  487. boolean fzsendcmd P((const char *z));
  488. char *zzgetspace P((int *pcdata));
  489. boolean fzsenddata P((char *z, int c));
  490. boolean fzprocess P((boolean *pfexit, long *plredo));
  491. boolean fzwait P((void));
  492. boolean fzfile P((boolean fstart, boolean fsend, long *plredo, long cbytes));
  493.  
  494. static boolean fzsend_data P((char *zdata, int cdata, boolean fendofmessage));
  495. static boolean fzstart_proto P((boolean fmaster));
  496. static int izexchange_init P((boolean fmaster, int send_type, achdrval_t send_val, achdrval_t recv_val));
  497. static boolean fzshutdown_proto P((void));
  498. static boolean fzstart_tx P((void));
  499. static boolean fzfinish_tx P((long *plredo));
  500. static boolean fzstart_rx P((void));
  501. static boolean fzfinish_rx P((void));
  502. static boolean fzsend_hdr P((int ipkttype, int ihdrtype, hdrval_t hdrval, boolean fcheckreceive));
  503. static boolean fzsend_data_packet P((char *zdata, int cdata, int frameend, boolean fcheckreceive));
  504. static int czbuild_header P((char *zresult, int ipkttype, int ihdrtype, hdrval_t hdrval));
  505. static int czbuild_data_packet P((char *zresult, const char *zdata, int cdata, int frameend));
  506. /*
  507.  * The rest of the functions do not follow Ian's naming style. I have left
  508.  * the names the same as the original zm source. Over time, they may change.
  509.  */
  510. static int izrecv_hdr P((achdrval_t hdr));    /* IE: zgethdr() */
  511. static int zrbhdr32 P((achdrval_t hdr));
  512. static int zrhhdr P((achdrval_t hdr));
  513. static int zrdat32 P((char *buf, int length, int *iprxcount));
  514. static int getinsync P((boolean flag));
  515. static char *zputhex P((char *p, int ch));
  516. static char *zputchar P((char *p, int ch));
  517. static int zgethex P((void));
  518. static int zdlread P((void));
  519. static int noxrd7 P((void));
  520. static int realreadchar P((int timeout));
  521. static boolean fzreceive_ready P((void));
  522. static void stohdr P((hdrval_t pos, achdrval_t hdr));
  523. static hdrval_t rclhdr P((achdrval_t hdr));
  524. static hdrval_t hvzencode_data_hdr P((winpos_t cbytes));
  525. static void zdecode_data_hdr P((hdrval_t hdrval, winpos_t *pcbytes));
  526. static winpos_t lzupdate_rxpos P((achdrval_t rx_hdr, winpos_t rxpos, winpos_t lrxpos, winpos_t txpos));
  527.  
  528. #ifdef THINK_C
  529.  
  530. #define READCHAR(b, i) b = realreadchar(i)
  531.  
  532. #else
  533.  
  534. /*
  535.  * This macro replaces readchar() because it achieves a noticable speed up. The
  536.  * readchar() function has been renamed realreadchar(). Thanks to Ian for
  537.  * running this stuff through a profiler to find this out. Ian suggests further
  538.  * speed ups may be obtained by doing a similar thing in zrdat32().
  539.  */
  540.  
  541. /* Assign the next character to b. */
  542. #define READCHAR(b, i) \
  543.   (iPrecstart != iPrecend \
  544.    ? ((b) = BUCHAR (abPrecbuf[iPrecstart]), \
  545.       iPrecstart = (iPrecstart + 1) % CRECBUFLEN) \
  546.    : ((b) = realreadchar (i)))
  547.  
  548. #endif
  549.  
  550. /************************************************************************/
  551.  
  552.  
  553.  
  554. /* 
  555.     And now for a thin layer of uupc glue on top of the a-protocol glue on
  556.    top of the ZMODEM code...
  557. */
  558.  
  559. int aopenpk(int master)
  560. {
  561.     pktsize = PKTSIZE;
  562.     msgtime = MSGTIME;
  563.     return fzstart(master);
  564. }
  565.  
  566. int aclosepk(void)
  567. {
  568.     return fzshutdown();
  569. }
  570.  
  571. int awrmsg(char *str, boolean nowait) /* nowait semantic not implemented yet */
  572. {
  573.     if (fzsendcmd(str)) {
  574.         return 0;
  575.     } else {
  576.         return -1;
  577.     }
  578. }
  579.  
  580. int asendresp(int state)
  581. {
  582.     return OK;
  583. }
  584.  
  585.  
  586.  
  587.  
  588.  
  589. /*
  590.  * Start the protocol ...
  591.  */
  592.  
  593. boolean
  594. fzstart(fmaster)
  595. boolean fmaster;
  596. {
  597. #ifndef THINK_C
  598.     if (!fport_set (PORTSETTING_EIGHT))
  599.         return FALSE;
  600. #endif
  601.  
  602.     printmsg (1, "Protocol 'a' starting: %d, %d, %d, %d, %d, %d",
  603.         cZtimeout, cZretries, cZstartup_retries,
  604.         cZmax_garbage, cZtx_window, fZesc_ctl);
  605.  
  606.     /*
  607.      * For now, we place tight restrictions on the size of the transmit
  608.      * window. This might be relaxed in the future. If it is relaxed,
  609.      * some of these tests will stay, some will go. That is why it is
  610.      * coded like it is.
  611.      */
  612.  
  613.     if (cZtx_window % 1024 != 0 ||
  614.         cZtx_window < 4096 || cZtx_window > 65536 ||
  615.         65536 % cZtx_window != 0
  616.     ) {
  617.         printmsg (0, "fzstart: cZtx_window not one of 4096, 8192, 16384, 32768, 65536");
  618.         return FALSE;
  619.     }
  620.  
  621.     zZtx_buf = (char *) xmalloc (CPACKETSIZE);
  622.  
  623.     zZtx_packet_buf = (char *) xmalloc (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 /*slop*/);
  624.     zZrx_packet_buf = (char *) xmalloc (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 /*slop*/);
  625.  
  626.     iZlast_tx_data_packet = -1;
  627.     iZlast_rx_data_packet = -1;
  628.  
  629.     wpZtxpos = wpZlrxpos = wpZrxpos = wpZrxbytes = 0;
  630.     cZtxwspac = cZtx_window / 4;
  631.  
  632.     cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
  633.     cZtimeouts = cZerrors = 0;
  634.  
  635.     iZpkt_rcvd_kludge = -1;
  636.  
  637. #if 0
  638.     /*
  639.      * We ensure <cZtx_window> is at least 4k, so the following is
  640.      * unnecessary. It can be put back in later if needed.
  641.      */
  642.     if (cZblklen_override > cZtxwspac || (!cZblklen_override && cZtxwspac < 1024))
  643.         cZblklen_override = cZtxwspac;
  644. #endif
  645.  
  646. #ifdef DJE_TESTING
  647.     {
  648.         extern int uucptest,uucptest2,uucptestseed;
  649.         FILE *f;
  650.  
  651.         if (uucptest == -1) {
  652.             if ((f = fopen ("/usr/local/src/bin/uucp/uucptest", "r")) != NULL) {
  653.                 fscanf (f, "%d %d %d",
  654.                     &uucptestseed, &uucptest, &uucptest2);
  655.                 fclose (f);
  656.             }
  657.             srand (uucptestseed);
  658.         }
  659.     }
  660. #endif
  661.  
  662.     /*
  663.      * Fire up the protocol (exchange init messages) ...
  664.      */
  665.  
  666.     if (!fzstart_proto (fmaster))
  667.         return FALSE;
  668.  
  669.     return TRUE;
  670. }
  671.  
  672. /*
  673.  * Stop the protocol ...
  674.  */
  675.  
  676. boolean
  677. fzshutdown()
  678. {
  679.     (void) fzshutdown_proto ();
  680.  
  681.     xfree ((pointer) zZtx_buf);
  682.     xfree ((pointer) zZtx_packet_buf);
  683.     xfree ((pointer) zZrx_packet_buf);
  684.     zZtx_buf = NULL;
  685.     zZtx_packet_buf = NULL;
  686.     zZrx_packet_buf = NULL;
  687.  
  688.     /*
  689.      * Print some informative statistics ...
  690.      *
  691.      * I use the word "messages" here instead of "headers" because the
  692.      * latter is jargonese.
  693.      */
  694.  
  695.     printmsg (1,
  696.         "Protocol 'a' messages: sent %lu, received %lu",
  697.         cZheaders_sent, cZheaders_received);
  698.     printmsg (1,
  699.         "Protocol 'a' packets: sent %lu, received %lu",
  700.         wpZtxpos / 1024, wpZrxbytes / 1024);
  701.     if (cZbytes_resent != 0 || cZtimeouts != 0 || cZerrors != 0)
  702.         printmsg (1,
  703.             "Protocol 'a' errors: bytes resent %lu, timeouts %lu, errors %lu",
  704.             cZbytes_resent, cZtimeouts, cZerrors);
  705.  
  706.     /*
  707.      * Reset all the parameters to their default values, so that the
  708.      * protocol parameters used for this connection do not affect the
  709.      * next one.
  710.      */
  711.  
  712.     cZtimeout = CTIMEOUT;
  713.     cZretries = CRETRIES;
  714.     cZstartup_retries = CSTARTUP_RETRIES;
  715.     cZmax_garbage = CGARBAGE;
  716.     cZtx_window = CSEND_WINDOW;
  717.     fZesc_ctl = FESCAPE_CONTROL;
  718.  
  719.     cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
  720.     cZtimeouts = cZerrors = 0;
  721.  
  722.     return TRUE;
  723. }
  724.  
  725. /*
  726.  * Send a command string ...
  727.  * We send everything up to and including the null byte.
  728.  *
  729.  * We assume the command will fit in the outgoing data buffer.
  730.  * FIXME: A valid assumption?
  731.  */
  732.  
  733. boolean
  734. fzsendcmd(z)
  735. const char *z;
  736. {
  737.     int n,clen;
  738.     long lredo;
  739.     char *zbuf;
  740.  
  741.     clen = strlen (z) + 1;
  742.  
  743.     printmsg (5, "fzsendcmd: sending command %s", z);
  744.  
  745.     if (!fzstart_tx ())    /* must be called before zzgetspace() */
  746.         return FALSE;
  747.  
  748.     if ((zbuf = zzgetspace (&n)) == NULL)
  749.         return FALSE;
  750.  
  751. #if DEBUG > 0
  752.     if (clen > n)
  753.         ulog (LOG_FATAL, "fzsendcmd: clen > n");
  754. #endif
  755.  
  756.     strcpy (zbuf, z);
  757.  
  758.     /*
  759.      * Send it out ...
  760.      */
  761.  
  762.     do {
  763.         if (!fzsend_data (zbuf, clen, TRUE))
  764.             return FALSE;
  765.         if (!fzfinish_tx (&lredo))
  766.             return FALSE;
  767.     } while (lredo >= 0);
  768.  
  769.     return TRUE;
  770. }
  771.  
  772. /*
  773.  * Allocate a packet to send out ...
  774.  *
  775.  * Note that 'z' has dynamic packet resizing and that <cZblklen> will range
  776.  * from 32 to 1024, in multiples of 2.
  777.  */
  778.  
  779. char *
  780. zzgetspace(pclen)
  781. int *pclen;
  782. {
  783.     *pclen = cZblklen;
  784.     return zZtx_buf;
  785. }
  786.  
  787. /*
  788.  * Send a block of data ...
  789.  *
  790.  * If (cdata == 0) then the end of the file has been reached.
  791.  */
  792.  
  793. boolean
  794. fzsenddata(zdata, cdata)
  795. char *zdata;
  796. int cdata;
  797. {
  798.     printmsg (5, "fzsenddata: %d bytes", cdata);
  799.  
  800.     return fzsend_data (zdata, cdata, cdata == 0);
  801. }
  802.  
  803. /*
  804.  * Send a block of data (command or file) ...
  805.  */
  806.  
  807. static boolean
  808. fzsend_data(zdata, cdata, fendofmessage)
  809. char *zdata;
  810. int cdata;
  811. boolean fendofmessage;
  812. {
  813.     int n;
  814.  
  815.     if (iZlast_tx_data_packet == -1 || iZlast_tx_data_packet == ZCRCW) {
  816.         cZtxwcnt = cZrxwcnt = 0;
  817.         iZjunk_count = 0;
  818.         if (!fzsend_hdr (ZBIN, ZDATA, hvzencode_data_hdr (wpZtxpos), TRUE))
  819.             return FALSE;
  820.     }
  821.  
  822.     n = cdata;
  823.  
  824.     if (fendofmessage)
  825.         iZlast_tx_data_packet = ZCRCF;
  826.     else if (iZjunk_count > 3)
  827.         iZlast_tx_data_packet = ZCRCW;
  828.     else if (wpZtxpos == wpZlastsync)
  829.         iZlast_tx_data_packet = ZCRCW;
  830.     else if (cZrx_buf_len && (cZrxwcnt += n) >= cZrx_buf_len)
  831.         iZlast_tx_data_packet = ZCRCW;
  832.     else if ((cZtxwcnt += n) >= cZtxwspac) {
  833.         iZlast_tx_data_packet = ZCRCQ;
  834.         cZtxwcnt = 0;
  835.     } else
  836.         iZlast_tx_data_packet = ZCRCG;
  837.  
  838.     if (++iZtleft > 3) {
  839.         iZtleft = 0;
  840.         if (cZblklen < 1024)
  841.             cZblklen *= 2;
  842. #if 0    /* <cZblklen_override> is currently unnecessary */
  843.         if (cZblklen_override && cZblklen > cZblklen_override)
  844.             cZblklen = cZblklen_override;
  845. #endif
  846.         if (cZblklen > 1024)
  847.             cZblklen = 1024;
  848.         if (cZrx_buf_len && cZblklen > cZrx_buf_len)
  849.             cZblklen = cZrx_buf_len;
  850.     }
  851.  
  852. #if DEBUG > 0
  853.     if (FDEBUGGING(DEBUG_PROTO)) {
  854.         const char *type;
  855.  
  856.         switch (iZlast_tx_data_packet) {
  857.         case ZCRCW: type = "ZCRCW"; break;
  858.         case ZCRCG: type = "ZCRCG"; break;
  859.         case ZCRCQ: type = "ZCRCQ"; break;
  860.         case ZCRCE: type = "ZCRCE"; break;
  861.         case ZCRCF: type = "ZCRCF"; break;
  862.         default : type = "UNKNOWN!!!"; break;
  863.         }
  864.         ulog (LOG_DEBUG, "fzsend_data: %s, pos 0x%lx, %d bytes",
  865.             type, wpZtxpos, n);
  866.     }
  867. #endif
  868.  
  869.     if (!fzsend_data_packet (zdata, n, iZlast_tx_data_packet, TRUE))
  870.         return FALSE;
  871.  
  872.     wpZtxpos += n;
  873.  
  874.     if (iZlast_tx_data_packet == ZCRCW) {
  875.         /*
  876.          * FIXME: Ideally this would be done in fzprocess. However, it
  877.          *    is only called if there is data pending which there
  878.          *    may not be yet. I could have patched fploop() a bit but
  879.          *    for now, I've done it like this.
  880.          */
  881.         switch (getinsync (FALSE)) {
  882.         case ZACK:
  883.             break;
  884.         case ZRPOS:
  885.             iZlast_tx_data_packet = -1; /* trigger ZDATA */
  886.             ffileclearerror (eSendfile);
  887.             if (!ffileseek (eSendfile, wpZrxpos - wpZtxstart, 0 /*SEEK_SET*/)) {
  888.                 printmsg (0, "seek: %s", strerror (errno));
  889.                 usendfile_error ();
  890.                 return FALSE;
  891.             }
  892.             break;
  893.         default:
  894.             return FALSE;
  895.         }
  896.         return TRUE;
  897.     }
  898.  
  899.     /*
  900.      * If we've reached the maximum transmit window size, let the
  901.      * receiver catch up ...
  902.      *
  903.      * I use (cZtx_window - 2048) to play it safe.
  904.      */
  905.  
  906.     while (wpZtxpos - wpZlrxpos >= cZtx_window - 2048) {
  907.         if (iZlast_tx_data_packet != ZCRCQ) {
  908.             if (!fzsend_data_packet (zdata, 0,
  909.                     iZlast_tx_data_packet = ZCRCQ, TRUE))
  910.                 return FALSE;
  911.         }
  912.         /*
  913.          * FIXME: I'd rather not call ffileseek() in this file. When we
  914.          *    start buffering the outgoing data, the following
  915.          *    ffileseek() will disappear.
  916.          */
  917.         switch (getinsync (TRUE)) {
  918.         case ZACK:
  919.             break;
  920.         case ZRPOS:
  921.             iZlast_tx_data_packet = -1; /* trigger ZDATA */
  922.             ffileclearerror (eSendfile);
  923.             if (!ffileseek (eSendfile, wpZrxpos - wpZtxstart, 0 /*SEEK_SET*/)) {
  924.                 printmsg (0, "seek: %s", strerror (errno));
  925.                 usendfile_error ();
  926.                 return FALSE;
  927.             }
  928.             break;
  929.         default:
  930.             return FALSE;
  931.         }
  932.     }
  933.  
  934.     return TRUE;
  935. }
  936.  
  937. /*
  938.  * Process existing data ...
  939.  * This function is only called when sending a file.
  940.  *
  941.  * Set *pfexit to TRUE if a file or a command has been
  942.  * completely received. (FIXME: not supported at present).
  943.  *
  944.  * If the protocol needs uucp to fseek() to some point, *plredo is set to
  945.  * that point. Otherwise it is -1L.
  946.  */
  947.  
  948. boolean
  949. fzprocess(pfexit, plredo)
  950. boolean *pfexit;
  951. long *plredo;
  952. {
  953.     int c,ch;
  954.  
  955.     *pfexit = FALSE;
  956.     *plredo = -1;
  957.  
  958.     while (fzreceive_ready ()) {
  959.         READCHAR (ch, 1);
  960.         switch (ch) {
  961.         case ZPAD:
  962.             /* see if we're detecting ZRPOS packets quickly */
  963.             printmsg (5, "fzprocess: possible ZRPOS packet");
  964.             c = getinsync (TRUE);
  965.             if (c == ZACK)
  966.                 break;
  967.             /* FIXME: sz does a TCFLSH here */
  968. #if 0    /* FIXME: Not sure if this is needed, or where to put it. */
  969.             /* ZCRCE - dinna wanna starta ping-pong game */
  970.             if (!fzsend_data_packet (zZtx_packet_buf, 0, ZCRCE, TRUE))
  971.                 return FALSE;
  972. #endif
  973.             if (c == ZRPOS) {
  974.                 *plredo = wpZrxpos - wpZtxstart;
  975.                 iZlast_tx_data_packet = -1; /* trigger ZDATA */
  976.                 break;    /* not returning is intentional */
  977.             }
  978.             return FALSE;
  979.         case XOFF:
  980.         case XOFF | 0200:
  981.             READCHAR (ch, XON_WAIT);
  982.             break;
  983.         case CR:
  984.             break;
  985.         default:
  986.             iZjunk_count++;
  987.             break;
  988.         }
  989.     }
  990.  
  991.     return TRUE;
  992. }
  993.  
  994. /*
  995.  * Wait for data to come in.
  996.  *
  997.  * This continues processing until a complete file or command has been
  998.  * received.
  999.  */
  1000.  
  1001. boolean
  1002. fzwait()
  1003. {
  1004.     int c,cerr,rxcount;
  1005.     boolean fexit;
  1006.     achdrval_t rx_hdr;
  1007.  
  1008.     if (!fzstart_rx ())
  1009.         return FALSE;
  1010.  
  1011.     cerr = cZretries;
  1012.  
  1013.     goto nxthdr;
  1014.  
  1015.     for (;;) {
  1016.         if (!fzsend_hdr (ZHEX, ZRPOS, hvzencode_data_hdr (wpZrxbytes), FALSE))
  1017.             return FALSE;
  1018. nxthdr:
  1019.         c = izrecv_hdr (rx_hdr);
  1020.  
  1021.         switch (c) {
  1022.         case ZM_TIMEOUT:
  1023.         case ZNAK:
  1024.             if (--cerr < 0) {
  1025.                 printmsg (0, "fzwait: retries exhausted");
  1026.                 return FALSE;
  1027.             }
  1028.             continue;
  1029.         case ZM_ERROR:
  1030.             if (--cerr < 0) {
  1031.                 printmsg (0, "fzwait: retries exhausted");
  1032.                 return FALSE;
  1033.             }
  1034.             /*fport_break ();*/
  1035.             continue;
  1036.         case ZM_RCDO:
  1037.         case ZFIN:
  1038.             return FALSE;
  1039.         case ZRPOS:
  1040.         case ZACK:
  1041.             goto nxthdr;    /* ignore, partner is out of sync */
  1042.         case ZDATA: {
  1043.             winpos_t rx_bytes;
  1044.  
  1045.             zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
  1046.             printmsg (5,
  1047.                 "fzwait: bytes(us,them) 0x%lx,0x%lx",
  1048.                 wpZrxbytes, rx_bytes);
  1049.             if (rx_bytes != wpZrxbytes) {
  1050.                 if (--cerr < 0) {
  1051.                     printmsg (0, "fzwait: retries exhausted");
  1052.                     return FALSE;
  1053.                 }
  1054.                 (void) zrdat32 (zZrx_packet_buf, 1024, &rxcount);
  1055.                 /*fport_break ();*/
  1056.                 /*
  1057.                  * FIXME: Seems to me we should ignore this one
  1058.                  *    and go for a timeout, the theory being
  1059.                  *    that the appropriate ZRPOS has already
  1060.                  *    been sent. We're obviously out of sync.
  1061.                  *    /dje 92Mar10
  1062.                  */
  1063.                 continue;    /* goto nxthdr? */
  1064.             }
  1065. moredata:
  1066.             /*
  1067.              * Do not call fgot_data() with (rxcount == 0) if it's
  1068.              * not ZCRCF. fgot_data() will erroneously think this
  1069.              * is the end of the message.
  1070.              */
  1071.             c = zrdat32 (zZrx_packet_buf, 1024, &rxcount);
  1072. #if DEBUG > 0
  1073.             if (FDEBUGGING(DEBUG_PROTO)) {
  1074.                 const char *msg;
  1075.  
  1076.                 if (c < 0) {
  1077.                     msg = ZZHEADER_NAME(c);
  1078.                 } else {
  1079.                     switch (c) {
  1080.                     case GOTCRCW: msg = "ZCRCW"; break;
  1081.                     case GOTCRCG: msg = "ZCRCG"; break;
  1082.                     case GOTCRCQ: msg = "ZCRCQ"; break;
  1083.                     case GOTCRCE: msg = "ZCRCE"; break;
  1084.                     case GOTCRCF: msg = "ZCRCF"; break;
  1085.                     default : msg = NULL; break;
  1086.                     }
  1087.                 }
  1088.                 if (msg != NULL)
  1089.                     ulog (LOG_DEBUG, "fzwait: zrdat32: %s, %d bytes", msg, rxcount);
  1090.                 else
  1091.                     ulog (LOG_DEBUG, "fzwait: zrdat32: %d, %d bytes", c, rxcount);
  1092.             }
  1093. #endif
  1094.             switch (c) {
  1095.             case ZM_ERROR:    /* CRC error */
  1096.                 cZerrors++;
  1097.                 if (--cerr < 0) {
  1098.                     printmsg (0, "fzwait: retries exhausted");
  1099.                     return FALSE;
  1100.                 }
  1101.                 /*fport_break ();*/
  1102.                 continue;
  1103.             case ZM_TIMEOUT:
  1104.                 cZtimeouts++;
  1105.                 if (--cerr < 0) {
  1106.                     printmsg (0, "fzwait: retries exhausted");
  1107.                     return FALSE;
  1108.                 }
  1109.                 continue;
  1110.             case ZM_RCDO:
  1111.                 return FALSE;
  1112.             case GOTCRCW:
  1113.                 iZlast_rx_data_packet = ZCRCW;
  1114.                 cerr = cZretries;
  1115.                 if (rxcount != 0 && !fgot_data (zZrx_packet_buf, rxcount, FALSE, FALSE, &fexit))
  1116.                     return FALSE;
  1117.                 wpZrxbytes += rxcount;
  1118.                 if (!fzsend_hdr (ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), FALSE))
  1119.                     return FALSE;
  1120.                 fsend_data (&xon, 1, FALSE);
  1121.                 goto nxthdr;
  1122.             case GOTCRCQ:
  1123.                 iZlast_rx_data_packet = ZCRCQ;
  1124.                 cerr = cZretries;
  1125.                 if (rxcount != 0 && !fgot_data (zZrx_packet_buf, rxcount, FALSE, FALSE, &fexit))
  1126.                     return FALSE;
  1127.                 wpZrxbytes += rxcount;
  1128.                 if (!fzsend_hdr (ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), FALSE))
  1129.                     return FALSE;
  1130.                 goto moredata;
  1131.             case GOTCRCG:
  1132.                 iZlast_rx_data_packet = ZCRCG;
  1133.                 cerr = cZretries;
  1134.                 if (rxcount != 0 && !fgot_data (zZrx_packet_buf, rxcount, FALSE, FALSE, &fexit))
  1135.                     return FALSE;
  1136.                 wpZrxbytes += rxcount;
  1137.                 goto moredata;
  1138.             case GOTCRCE:
  1139.                 iZlast_rx_data_packet = ZCRCE;
  1140.                 cerr = cZretries;
  1141.                 if (rxcount != 0 && !fgot_data (zZrx_packet_buf, rxcount, FALSE, FALSE, &fexit))
  1142.                     return FALSE;
  1143.                 wpZrxbytes += rxcount;
  1144.                 goto nxthdr;
  1145.             case GOTCRCF:
  1146.                 iZlast_rx_data_packet = ZCRCF;
  1147.                 /*
  1148.                  * fzfinish_rx() must be called before
  1149.                  * fgot_data() because fgot_data() will send
  1150.                  * out a UUCP-command but the sender won't be
  1151.                  * ready for it until it receives our final
  1152.                  * ZACK.
  1153.                  */
  1154.                 cerr = cZretries;
  1155.                 wpZrxbytes += rxcount;
  1156.                 if (!fzfinish_rx ())
  1157.                     return FALSE;
  1158.                 if (!fgot_data (zZrx_packet_buf, rxcount, FALSE, FALSE, &fexit))
  1159.                     return FALSE;
  1160.                 /* FIXME: Examine <fexit>? Or maybe ensure it's TRUE? */
  1161.                 return TRUE;
  1162.             }
  1163.             return FALSE;
  1164.         }
  1165.         default:
  1166.             printmsg (0, "fzwait: received header %s",
  1167.                 ZZHEADER_NAME(c));
  1168.             return FALSE;
  1169.         }
  1170.     }
  1171.  
  1172.     return TRUE;
  1173. }
  1174.  
  1175. /*
  1176.  * File level routine. Called when initiating/terminating file transfers.
  1177.  *
  1178.  * When starting to send a file:    (TRUE, TRUE, NULL, cbytes)
  1179.  * When starting to receive a file:    (TRUE, FALSE, NULL, -1)
  1180.  * When send EOF, check resend:        (FALSE, TRUE, &lredo, -1)
  1181.  * When receive EOF, check re-receive:    (FALSE, FALSE, &fredo, -1)
  1182.  */
  1183.  
  1184. boolean
  1185. fzfile(fstart, fsend, plredo, cbytes)
  1186. boolean fstart;
  1187. boolean fsend;
  1188. long *plredo;
  1189. long cbytes;
  1190. {
  1191.     printmsg (5, "fzfile: fstart=%d, fsend=%d", fstart, fsend);
  1192.     if (plredo != NULL)
  1193.         *plredo = -1;
  1194.  
  1195.     if (fsend) {
  1196.         if (fstart)
  1197.             return fzstart_tx ();
  1198.         return fzfinish_tx (plredo);
  1199.     }
  1200.  
  1201.     return TRUE;
  1202. }
  1203.  
  1204. /****************************************************************************/
  1205.  
  1206.  
  1207. #if 0    /* not used, we only use 32 bit crc's */
  1208. /*
  1209.  * crctab calculated by Mark G. Mendel, Network Systems Corporation
  1210.  */
  1211.  
  1212. static unsigned short crctab[256] = {
  1213.     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  1214.     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  1215.     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  1216.     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  1217.     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  1218.     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  1219.     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  1220.     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  1221.     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  1222.     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  1223.     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  1224.     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  1225.     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  1226.     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  1227.     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  1228.     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  1229.     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  1230.     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  1231.     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  1232.     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  1233.     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  1234.     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  1235.     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  1236.     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  1237.     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  1238.     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  1239.     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  1240.     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  1241.     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  1242.     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  1243.     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  1244.     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
  1245. };
  1246. #endif    /* crctab */
  1247.  
  1248. /*
  1249.  * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
  1250.  * code or tables extracted from it, as desired without restriction.
  1251.  */
  1252.  
  1253. /* First, the polynomial itself and its table of feedback terms.  The  */
  1254. /* polynomial is                                                       */
  1255. /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
  1256. /* Note that we take it "backwards" and put the highest-order term in  */
  1257. /* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
  1258. /* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
  1259. /* the MSB being 1.                                                    */
  1260.  
  1261. /* Note that the usual hardware shift register implementation, which   */
  1262. /* is what we're using (we're merely optimizing it by doing eight-bit  */
  1263. /* chunks at a time) shifts bits into the lowest-order term.  In our   */
  1264. /* implementation, that means shifting towards the right.  Why do we   */
  1265. /* do it this way?  Because the calculated CRC must be transmitted in  */
  1266. /* order from highest-order term to lowest-order term.  UARTs transmit */
  1267. /* characters in order from LSB to MSB.  By storing the CRC this way,  */
  1268. /* we hand it to the UART in the order low-byte to high-byte; the UART */
  1269. /* sends each low-bit to hight-bit; and the result is transmission bit */
  1270. /* by bit from highest- to lowest-order term without requiring any bit */
  1271. /* shuffling on our part.  Reception works similarly.                  */
  1272.  
  1273. /* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
  1274. /*                                                                     */
  1275. /*     The table can be generated at runtime if desired; code to do so */
  1276. /*     is shown later.  It might not be obvious, but the feedback      */
  1277. /*     terms simply represent the results of eight shift/xor opera-    */
  1278. /*     tions for all combinations of data and CRC register values.     */
  1279. /*                                                                     */
  1280. /*     The values must be right-shifted by eight bits by the "updcrc"  */
  1281. /*     logic; the shift must be unsigned (bring in zeroes).  On some   */
  1282. /*     hardware you could probably optimize the shift in assembler by  */
  1283. /*     using byte-swap instructions.                                   */
  1284.  
  1285. const static long crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
  1286. 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
  1287. 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
  1288. 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
  1289. 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
  1290. 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  1291. 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
  1292. 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
  1293. 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
  1294. 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
  1295. 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  1296. 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
  1297. 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
  1298. 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
  1299. 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
  1300. 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  1301. 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
  1302. 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
  1303. 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
  1304. 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
  1305. 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  1306. 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
  1307. 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
  1308. 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
  1309. 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
  1310. 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  1311. 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
  1312. 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
  1313. 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
  1314. 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
  1315. 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  1316. 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
  1317. 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
  1318. };
  1319.  
  1320. /*
  1321.  * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. 
  1322.  *  NOTE: First argument must be in range 0 to 255.
  1323.  *        Second argument is referenced twice.
  1324.  * 
  1325.  * Programmers may incorporate any or all code into their programs, 
  1326.  * giving proper credit within the source. Publication of the 
  1327.  * source routines is permitted so long as proper credit is given 
  1328.  * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, 
  1329.  * Omen Technology.
  1330.  */
  1331.  
  1332. #define updcrc(cp, crc) (crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
  1333. #define UPDC32(b, crc) (crc_32_tab[((int) (crc) ^ (b)) & 0xff] ^ (((crc) >> 8) & 0x00ffffffL))
  1334.  
  1335. /****************************************************************************/
  1336.  
  1337. /*
  1338.  * This section contains the guts of the Zmodem protocol. The intention
  1339.  * is to leave as much of it alone as possible at the start. Overtime it
  1340.  * will be cleaned up (EG: I'd like to clean up the naming of the globals).
  1341.  * Also, Zmodem has a different coding style. Over time this will be converted
  1342.  * to the Taylor UUCP coding style.
  1343.  */
  1344.  
  1345. /*
  1346.  * Start the protocol (exchange init packets) ...
  1347.  *
  1348.  * UUCP can transfer files in both directions in one session. Therefore the
  1349.  * init sequence is a little different.
  1350.  *
  1351.  * 1) ZINIT packets are exchanged
  1352.  *    - contains protocol version and protocol flags
  1353.  * 2) ZDATA packets are exchanged
  1354.  *    - is intended to contain various numeric and string information
  1355.  * 3) ZACK packets are exchanged
  1356.  * 4) ZINITEND packets are exchanged
  1357.  *
  1358.  * As with 'g', we ignore <fmaster>.
  1359.  */
  1360.  
  1361. static boolean
  1362. fzstart_proto(fmaster)
  1363. boolean fmaster;
  1364. {
  1365.     int i,n;
  1366.     achdrval_t tx_hdr,rx_hdr;
  1367.  
  1368.     for (i = 0; i < cZstartup_retries; i++) {
  1369.         stohdr (0L, tx_hdr);
  1370.         tx_hdr[ZF0] = ZPROTOCOL_VERSION;
  1371.         if (fZesc_ctl)
  1372.             tx_hdr[ZF1] |= TX_ESCCTL;
  1373.         switch (izexchange_init (fmaster, ZINIT, tx_hdr, rx_hdr)) {
  1374.         case -1: return FALSE;
  1375.         case 0:  continue;
  1376.         case 1:  break;
  1377.         }
  1378. #if 0    /* can't work, but kept for documentation */
  1379.         if (rx_hdr[ZF0] == 0) {
  1380.             printmsg (0, "Old protocol version, init failed");
  1381.             return FALSE;
  1382.         }
  1383. #endif
  1384.         fZesc_ctl = fZesc_ctl || (rx_hdr[ZF1] & TX_ESCCTL) != 0;
  1385.  
  1386.         stohdr (0L, tx_hdr);
  1387.         switch (izexchange_init (fmaster, ZDATA, tx_hdr, rx_hdr)) {
  1388.         case -1: return FALSE;
  1389.         case 0:  continue;
  1390.         case 1:  break;
  1391.         }
  1392.  
  1393.         stohdr (0L, tx_hdr);
  1394.         switch (izexchange_init (fmaster, ZACK, tx_hdr, rx_hdr)) {
  1395.         case -1: return FALSE;
  1396.         case 0:  continue;
  1397.         case 1:  break;
  1398.         }
  1399.  
  1400.         stohdr (0L, tx_hdr);
  1401.         switch (izexchange_init (fmaster, ZINITEND, tx_hdr, rx_hdr)) {
  1402.         case -1: return FALSE;
  1403.         case 0:  continue;
  1404.         case 1:  break;
  1405.         }
  1406.  
  1407.         printmsg (5, "fzstart_proto: Protocol started");
  1408.         return TRUE;
  1409.  
  1410.         /* FIXME: see protg.c regarding sequencing here. */
  1411.     }
  1412.  
  1413.     printmsg (0, "Protocol init failed");
  1414.     return FALSE;
  1415. }
  1416.  
  1417. /*
  1418.  * Exchange init messages. This is based on 'g'.
  1419.  * See the comments concerning fgexchange_init() in protg.c.
  1420.  *
  1421.  * We return 1 for success, 0 for restart, -1 for comm failure (terminate).
  1422.  */
  1423.  
  1424. static int
  1425. izexchange_init(fmaster, send_type, send_val, recv_val)
  1426. boolean fmaster;
  1427. int send_type;
  1428. achdrval_t send_val;
  1429. achdrval_t recv_val;
  1430. {
  1431.     int i,recv_type,count;
  1432.  
  1433.     for (i = 0; i < CEXCHANGE_INIT_RETRIES; i++) {
  1434.         if (!fzsend_hdr (send_type == ZDATA ? ZBIN : ZHEX,
  1435.                 send_type, rclhdr (send_val), FALSE))
  1436.             return -1;
  1437.  
  1438.         /*
  1439.          * The ZDATA packet is intended to contain the <Attn> string
  1440.          * (eventually, if it's ever usable) and allow for anything
  1441.          * else that will need to be thrown in.
  1442.          */
  1443.  
  1444.         if (send_type == ZDATA) {
  1445.             count = czbuild_data_packet (zZtx_packet_buf, "", 1, ZCRCF);
  1446.             if (!fsend_data (zZtx_packet_buf, count, FALSE))
  1447.                 return -1;
  1448.         }
  1449.  
  1450.         recv_type = izrecv_hdr (recv_val);
  1451.  
  1452.         switch (recv_type) {
  1453.         case ZM_TIMEOUT:
  1454.         case ZM_ERROR:
  1455.             continue;
  1456.         case ZM_RCDO:
  1457.         case ZFIN:
  1458.             return -1;
  1459.         case ZINIT:
  1460.         case ZACK:
  1461.         case ZINITEND:
  1462.             break;
  1463.         case ZDATA:
  1464.             if (zrdat32 (zZrx_packet_buf, 1024, &count) == GOTCRCF)
  1465.                 break;
  1466.             continue;
  1467.         default:
  1468.             continue;
  1469.         }
  1470.  
  1471.         if (recv_type == send_type)
  1472.             return 1;
  1473.  
  1474.         /*
  1475.          * If the other side is farther along than we are, we have lost
  1476.          * a packet.  Fall immediately back to ZINIT (but don't fail
  1477.          * if we are already doing ZINIT, since that would count
  1478.          * against cStart_retries more than it should).
  1479.          *
  1480.          * FIXME: The ">" test is "<" in protg.c. Check who's right.
  1481.          */
  1482.  
  1483.         if (recv_type > send_type && send_type != ZINIT)
  1484.             return 0;
  1485.  
  1486.         /*
  1487.          * If we are sending ZINITEND and we receive an ZINIT, the
  1488.          * other side has falled back (we know this because we have
  1489.          * seen a ZINIT from them).  Fall back ourselves to start
  1490.          * the whole handshake over again.
  1491.          */
  1492.  
  1493.         if (recv_type == ZINIT && send_type == ZINITEND)
  1494.             return 0;
  1495.     }
  1496.  
  1497.     return 0;
  1498. }
  1499.  
  1500. /*
  1501.  * Shut down the protocol ...
  1502.  */
  1503.  
  1504. static boolean
  1505. fzshutdown_proto()
  1506. {
  1507.     (void) fzsend_hdr (ZHEX, ZFIN, 0L, FALSE);
  1508.     return TRUE;
  1509. }
  1510.  
  1511. /*
  1512.  * Reset the transmitter side for sending a new message ...
  1513.  */
  1514.  
  1515. static boolean
  1516. fzstart_tx()
  1517. {
  1518.     iZlast_tx_data_packet = -1;
  1519.  
  1520.     /*
  1521.      * <wpZlastsync> is set to -1L to suppress ZCRCW request otherwise
  1522.      * triggered by (wpZlastsync == wpZtxpos).
  1523.      */
  1524.  
  1525.     cZblklen = 1024;
  1526.     wpZlastsync = -1L;
  1527.     iZbeenhereb4 = 0;
  1528.     iZtleft = 0;
  1529.     iZjunk_count = 0;
  1530.  
  1531.     wpZtxpos = wpZtxpos + 1024L & ~1023L;    /* next packet boundary */
  1532.     wpZlrxpos = wpZrxpos = wpZtxpos;
  1533.  
  1534.     wpZtxstart = wpZtxpos;    /* so we can compute the "file offset" */
  1535.  
  1536.     return TRUE;
  1537. }
  1538.  
  1539. /*
  1540.  * Finish the sending of a message ...
  1541.  *
  1542.  * Basically, we wait for some indication that the receiver received our last
  1543.  * message. If the receiver tells us to restart from some point, we set
  1544.  * *plredo to that point.
  1545.  *
  1546.  * FIXME: This function is a major kludge at the moment. It is taken from
  1547.  *    getinsync(). It is necessary because I don't yet buffer outgoing data.
  1548.  *    It will go away when we do (buffer outgoing data).
  1549.  */
  1550.  
  1551. static boolean
  1552. fzfinish_tx(long *plredo)
  1553. {
  1554.     int c,cerr,ctimeouts;
  1555.     achdrval_t rx_hdr;
  1556.     winpos_t rx_bytes;
  1557.  
  1558.     *plredo = -1;
  1559.     cerr = cZretries;
  1560.     ctimeouts = 0;
  1561.  
  1562.     printmsg (5,
  1563.         "fzfinish_tx: txpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, rxbytes=0x%lx",
  1564.         wpZtxpos, wpZrxpos, wpZlrxpos, wpZrxbytes);
  1565.  
  1566.     for (;;) {
  1567.         c = izrecv_hdr (rx_hdr);
  1568.  
  1569.         switch (c) {
  1570.         case ZRPOS:
  1571.             wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos);
  1572.             /*
  1573.              * If the receiver sends a ZRPOS for the 1k block after
  1574.              * the one we're currently at, we lost the final ZACK.
  1575.              * We cheat and ignore this ZRPOS. Remember: the theory
  1576.              * is that this entire function will go away when we
  1577.              * begin buffering the outgoing data. Of course, one
  1578.              * can reword the protocol definition and say this
  1579.              * isn't cheating at all.
  1580.              */
  1581.             if ((wpZtxpos + 1024 & ~1023) == wpZrxpos)
  1582.                 return TRUE;
  1583.             cZbytes_resent += wpZtxpos - wpZrxpos;
  1584.             wpZlrxpos = wpZtxpos = wpZrxpos;
  1585.             if (wpZlastsync == wpZrxpos) {
  1586.                 if (++iZbeenhereb4 > 4)
  1587.                     if (cZblklen > 32)
  1588.                         cZblklen /= 2;
  1589.                 /* FIXME: shouldn't we reset iZbeenhereb4? */
  1590.             }
  1591.             wpZlastsync = wpZrxpos;
  1592.             iZlast_tx_data_packet = ZCRCW; /* force a timeout */
  1593.             *plredo = wpZrxpos - wpZtxstart;
  1594.             return TRUE;
  1595.         case ZACK:
  1596.             wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos);
  1597.             wpZlrxpos = wpZrxpos;
  1598.             if (wpZtxpos == wpZrxpos)    /* is this the ACK we want? */
  1599.                 return TRUE;
  1600.             break;
  1601.         case ZDATA:
  1602.             /*
  1603.              * We cheat here and take advantage of UUCP's current
  1604.              * half duplex nature. If we get a ZDATA starting on
  1605.              * the next 1k boundary, we lost the ZACK. We cheat and
  1606.              * tuck it away so that izrecv_hdr() can later detect
  1607.              * it. Remember: see above.
  1608.              */
  1609.             zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
  1610.             if ((wpZrxbytes + 1024L & ~1023L) == rx_bytes) {
  1611.                 iZpkt_rcvd_kludge = ZDATA;
  1612.                 hvZpkt_hdrval_kludge = rclhdr (rx_hdr);
  1613.                 return TRUE;
  1614.             }
  1615.             break;    /* ignore, out of sync (old) */
  1616.         case ZNAK:
  1617.             /*
  1618.              * We cheat here and take advantage of UUCP's current
  1619.              * half duplex nature. If we get a ZNAK starting on
  1620.              * the next 1k boundary, we lost the ZACK. We cheat and
  1621.              * throw the ZNAK away. Remember: see above.
  1622.              *
  1623.              * On the other hand, if (rx_bytes == wpZrxbytes) then
  1624.              * the other side is also in fzfinish_tx(). He must
  1625.              * have lost our ZACK, so we send him another.
  1626.              */
  1627.             zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
  1628.             if ((wpZrxbytes + 1024L & ~1023L) == rx_bytes)
  1629.                 return TRUE;
  1630.             if (rx_bytes == wpZrxbytes) {
  1631.                 if (!fzsend_hdr (ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), TRUE))
  1632.                     return FALSE;
  1633.             }
  1634.             break;    /* ignore, out of sync (old) */
  1635.         case ZFIN:
  1636.         case ZM_RCDO:
  1637.             return FALSE;
  1638.         case ZM_TIMEOUT:
  1639.             if (--cerr < 0) {
  1640.                 printmsg (0, "fzfinish_tx: retries exhausted");
  1641.                 return FALSE;
  1642.             }
  1643.             /*
  1644.              * Normally the sender doesn't send NAK's for timeouts.
  1645.              * We have to here because of the following scenario:
  1646.              *
  1647.              * - We send ZDATA/ZCRCF
  1648.              * - They send ZACK (corrupted)
  1649.              * - They send ZDATA/ZCRCF (corrupted)
  1650.              *
  1651.              * At this point, both sides are in fzfinish_tx().
  1652.              * We only send ZNAK every second timeout to increase
  1653.              * our timeout delay vs. our partner. This tries to
  1654.              * avoid ZRPOS and ZNAK "passing in transit".
  1655.              */
  1656.             if (++ctimeouts % 2 == 0)
  1657.                 if (!fzsend_hdr (ZHEX, ZNAK, hvzencode_data_hdr (wpZtxpos), TRUE))
  1658.                     return FALSE;
  1659.             break;
  1660.         case ZM_ERROR:
  1661.         default:
  1662.             if (--cerr < 0) {
  1663.                 printmsg (0, "fzfinish_tx: retries exhausted");
  1664.                 return FALSE;
  1665.             }
  1666.             if (!fzsend_hdr (ZHEX, ZNAK, hvzencode_data_hdr (wpZtxpos), TRUE))
  1667.                 return FALSE;
  1668.             break;
  1669.         }
  1670.     }
  1671. }
  1672.  
  1673. /*
  1674.  * Initialize the receiver ...
  1675.  */
  1676.  
  1677. static boolean
  1678. fzstart_rx()
  1679. {
  1680.     wpZrxbytes = wpZrxbytes + 1024L & ~1023L; /* next packet boundary */
  1681.  
  1682.     return TRUE;
  1683. }
  1684.  
  1685. /*
  1686.  * Terminate the receiver ...
  1687.  *
  1688.  * Acknowledge the last packet received.
  1689.  */
  1690.  
  1691. static boolean
  1692. fzfinish_rx()
  1693. {
  1694.     printmsg (5, "fzfinish_rx: message/file received");
  1695.  
  1696.     return fzsend_hdr (ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), FALSE);
  1697. }
  1698.  
  1699. /*
  1700.  * Send a Zmodem header to our partner ...
  1701.  */
  1702.  
  1703. static boolean
  1704. fzsend_hdr(ipkttype, ihdrtype, hdrval, fcheckreceive)
  1705. int ipkttype;
  1706. int ihdrtype;
  1707. hdrval_t hdrval;
  1708. boolean fcheckreceive;
  1709. {
  1710.     int cpacketlen;
  1711.  
  1712.     printmsg (5, "fzsend_hdr: %s, data = 0x%lx",
  1713.         ZZHEADER_NAME(ihdrtype), hdrval);
  1714.  
  1715.     cpacketlen = czbuild_header (zZtx_packet_buf, ipkttype, ihdrtype, hdrval);
  1716.  
  1717. #ifdef DJE_TESTING
  1718. #if 0
  1719.     if (ihdrtype == ZACK && rand () % 100 < uucptest2) {
  1720.         cZheaders_sent++;
  1721.         return TRUE;
  1722.     }
  1723. #else
  1724.     if (ihdrtype == ZACK || ihdrtype == ZDATA) {
  1725.         boolean fresult;
  1726.         int old;
  1727.         extern int uucptest,uucptest2;
  1728.  
  1729.         old = uucptest;
  1730.         uucptest = uucptest2;
  1731.         cZheaders_sent++;
  1732.         fresult = fsend_data (zZtx_packet_buf, cpacketlen, fcheckreceive);
  1733.         uucptest = old;
  1734.         return fresult;
  1735.     }
  1736. #endif
  1737. #endif
  1738.     cZheaders_sent++;
  1739.     return fsend_data (zZtx_packet_buf, cpacketlen, fcheckreceive);
  1740. }
  1741.  
  1742. /*
  1743.  * Send a data packet to our partner ...
  1744.  * <frameend> is one of ZCRCx.
  1745.  */
  1746.  
  1747. static boolean
  1748. fzsend_data_packet(zdata, cdata, frameend, fcheckreceive)
  1749. char *zdata;
  1750. int cdata;
  1751. int frameend;
  1752. boolean fcheckreceive;
  1753. {
  1754.     int cpacketlen;
  1755.  
  1756.     cpacketlen = czbuild_data_packet (zZtx_packet_buf, zdata, cdata, frameend);
  1757.  
  1758.     return fsend_data (zZtx_packet_buf, cpacketlen, fcheckreceive);
  1759. }
  1760.  
  1761. /*
  1762.  * Build Zmodem headers ...
  1763.  *
  1764.  * Note that we use 32 bit CRC's for ZHEX headers.
  1765.  *
  1766.  * This function is a combination of zm fns: zsbhdr(), zsbh32(), and zshhdr().
  1767.  */
  1768.  
  1769. static int
  1770. czbuild_header(zresult, ipkttype, ihdrtype, hdrval)
  1771. char *zresult;
  1772. int ipkttype;
  1773. int ihdrtype;
  1774. hdrval_t hdrval;
  1775. {
  1776.     char *p;
  1777.     int i;
  1778.     long crc;
  1779.     achdrval_t achdrval;
  1780.  
  1781.     p = zresult;
  1782.  
  1783.     switch (ipkttype) {
  1784.     case ZBIN:
  1785.         *p++ = ZPAD;
  1786.         *p++ = ZDLE;
  1787.         *p++ = ZBIN;
  1788.         p = zputchar (p, ihdrtype);
  1789.         crc = 0xffffffffL;
  1790.         crc = UPDC32 (ihdrtype, crc);
  1791.         stohdr (hdrval, achdrval);
  1792.         for (i = 0; i < 4; i++) {
  1793.             p = zputchar (p, achdrval[i]);
  1794.             crc = UPDC32 (achdrval[i], crc);
  1795.         }
  1796.         crc = ~crc;
  1797.         for (i = 0; i < 4; i++) {
  1798.             p = zputchar (p, (char) crc);
  1799.             crc >>= 8;
  1800.         }
  1801.         break;
  1802.     case ZHEX:     /* build hex header */
  1803.         *p++ = ZPAD;
  1804.         *p++ = ZPAD;
  1805.         *p++ = ZDLE;
  1806.         *p++ = ZHEX;
  1807.         p = zputhex (p, ihdrtype);
  1808.         crc = 0xffffffffL;
  1809.         crc = UPDC32 (ihdrtype, crc);
  1810.         stohdr (hdrval, achdrval);
  1811.         for (i = 0; i < 4; i++) {
  1812.             p = zputhex (p, achdrval[i]);
  1813.             crc = UPDC32 (achdrval[i], crc);
  1814.         }
  1815.         crc = ~crc;
  1816.         for (i = 0; i < 4; i++) {
  1817.             p = zputhex (p, (char) crc);
  1818.             crc >>= 8;
  1819.         }
  1820.         *p++ = CR;
  1821.         /*
  1822.          * Uncork the remote in case a fake XOFF has stopped data flow.
  1823.          */
  1824.         if (ihdrtype != ZFIN && ihdrtype != ZACK) /* FIXME: why? */
  1825.             *p++ = XON;
  1826.         break;
  1827.     default:
  1828.         printmsg (0, "czbuild_header: ipkttype == %d", ipkttype);
  1829.         break;
  1830.     }
  1831.  
  1832.     return p - zresult;
  1833. }
  1834.  
  1835. /*
  1836.  * Build Zmodem data packets ...
  1837.  *
  1838.  * This function is zsdata() and zsda32() from the zm source.
  1839.  */
  1840.  
  1841. static int
  1842. czbuild_data_packet(zresult, zdata, cdata, frameend)
  1843. char *zresult;
  1844. const char *zdata;
  1845. int cdata;
  1846. int frameend;
  1847. {
  1848.     char *p;
  1849.     long crc;
  1850.  
  1851.     p = zresult;
  1852.  
  1853.     crc = 0xffffffffL;
  1854.     for ( ; --cdata >= 0; zdata++) {
  1855.         char c;
  1856.  
  1857.         c = *zdata;
  1858.         if (c & 0140)
  1859.             *p++ = c;
  1860.         else
  1861.             p = zputchar (p, c);
  1862.         crc = UPDC32 ((unsigned char) c, crc);
  1863.     }
  1864.     *p++ = ZDLE;
  1865.     *p++ = frameend;
  1866.     crc = UPDC32 (frameend, crc);
  1867.     crc = ~crc;
  1868.     for (cdata = 0; cdata < 4; cdata++) {
  1869.         p = zputchar (p, (char) crc);
  1870.         crc >>= 8;
  1871.     }
  1872.     if (frameend == ZCRCW || frameend == ZCRCE || frameend == ZCRCF) {
  1873.         *p++ = CR;
  1874.         *p++ = XON;
  1875.     }
  1876.  
  1877.     return p - zresult;
  1878. }
  1879.  
  1880. /*
  1881.  * Read in a header ...
  1882.  *
  1883.  * This is function zgethdr() from the Zmodem source.
  1884.  */
  1885.  
  1886. static int
  1887. izrecv_hdr(hdr)
  1888. achdrval_t hdr;
  1889. {
  1890.     int c,cerr;
  1891.  
  1892.     /*
  1893.      * Kludge alert! If another part of the program received a packet but
  1894.      * wasn't ready to handle it, it is tucked away for us to handle now.
  1895.      */
  1896.  
  1897.     if (iZpkt_rcvd_kludge != -1) {
  1898.         c = iZpkt_rcvd_kludge;
  1899.         iZpkt_rcvd_kludge = -1;
  1900.         stohdr (hvZpkt_hdrval_kludge, hdr);
  1901.         printmsg (5,
  1902.             "izrecv_hdr: queued %s, data = 0x%lx",
  1903.             ZZHEADER_NAME(c), rclhdr (hdr));
  1904.         cZheaders_received++;
  1905.         return c;
  1906.     }
  1907.  
  1908.     cerr = cZmax_garbage;    /* Max bytes before start of frame */
  1909.  
  1910. again:
  1911.     switch (c = noxrd7 ()) {
  1912.     case ZM_TIMEOUT:
  1913.     case ZM_ERROR:
  1914.     case ZM_RCDO:
  1915.         goto fifi;
  1916.     case ZPAD:        /* This is what we want */
  1917.         break;
  1918.     case CR:        /* padding at end of previous header */
  1919.     default:
  1920.         if (--cerr < 0) {
  1921.             c = ZM_ERROR;
  1922.             goto fifi;
  1923.         }
  1924.         goto again;
  1925.     }
  1926.  
  1927. splat:
  1928.     switch (c = noxrd7 ()) {
  1929.     case ZPAD:
  1930.         if (--cerr < 0) {
  1931.             c = ZM_ERROR;
  1932.             goto fifi;
  1933.         }
  1934.         goto splat;
  1935.     case ZM_TIMEOUT:
  1936.     case ZM_RCDO:
  1937.         goto fifi;
  1938.     case ZDLE:        /* This is what we want */
  1939.         break;
  1940.     default:
  1941.         if (--cerr < 0) {
  1942.             c = ZM_ERROR;
  1943.             goto fifi;
  1944.         }
  1945.         goto again;
  1946.     }
  1947.  
  1948.     switch (c = noxrd7 ()) {
  1949.     case ZM_TIMEOUT:
  1950.     case ZM_RCDO:
  1951.         goto fifi;
  1952.     case ZBIN:
  1953.         c = zrbhdr32 (hdr);
  1954.         break;
  1955.     case ZHEX:
  1956.         c = zrhhdr (hdr);
  1957.         break;
  1958.     default:
  1959.         if (--cerr < 0) {
  1960.             c = ZM_ERROR;
  1961.             goto fifi;
  1962.         }
  1963.         goto again;
  1964.     }
  1965.  
  1966. fifi:
  1967.     switch (c) {
  1968.     case ZM_TIMEOUT:
  1969.         cZtimeouts++;
  1970.         break;
  1971.     case ZM_ERROR:
  1972.         cZerrors++;
  1973.         break;
  1974.     case ZM_RCDO:
  1975.         break;
  1976.     default:
  1977.         cZheaders_received++;
  1978.         break;
  1979.     }
  1980.     printmsg (5, "izrecv_hdr: %s, data = 0x%x",
  1981.         ZZHEADER_NAME(c), rclhdr (hdr));
  1982.  
  1983.     return c;
  1984. }
  1985.  
  1986. /*
  1987.  * Receive a binary style header (type and position) with 32 bit FCS ...
  1988.  */
  1989.  
  1990. static int
  1991. zrbhdr32(hdr)
  1992. achdrval_t hdr;
  1993. {
  1994.     int c,i,type;
  1995.     long crc;
  1996.  
  1997.     if ((c = zdlread ()) & ~0377)
  1998.         return c;
  1999.     type = c;
  2000.     crc = 0xffffffffL;
  2001.     crc = UPDC32 (c, crc);
  2002.  
  2003.     for (i = 0; i < 4; i++) {
  2004.         if ((c = zdlread ()) & ~0377)
  2005.             return c;
  2006.         crc = UPDC32 (c, crc);
  2007.         hdr[i] = (char) c;
  2008.     }
  2009.     for (i = 0; i < 4; i++) {
  2010.         if ((c = zdlread ()) & ~0377)
  2011.             return c;
  2012.         crc = UPDC32 (c, crc);
  2013.     }
  2014.     if (crc != 0xDEBB20E3L)
  2015.         return ZM_ERROR;
  2016.  
  2017.     return type;
  2018. }
  2019.  
  2020. /*
  2021.  * Receive a hex style header (type and position) ...
  2022.  */
  2023.  
  2024. static int
  2025. zrhhdr(hdr)
  2026. achdrval_t hdr;
  2027. {
  2028.     int c,i,type;
  2029.     long crc;
  2030.  
  2031.     if ((c = zgethex ()) < 0)
  2032.         return c;
  2033.     type = c;
  2034.     crc = 0xffffffffL;
  2035.     crc = UPDC32 (c, crc);
  2036.  
  2037.     for (i = 0; i < 4; i++) {
  2038.         if ((c = zgethex ()) < 0)
  2039.             return c;
  2040.         crc = UPDC32 (c, crc);
  2041.         hdr[i] = (char) c;
  2042.     }
  2043.     for (i = 0; i < 4; i++) {
  2044.         if ((c = zgethex ()) < 0)
  2045.             return c;
  2046.         crc = UPDC32 (c, crc);
  2047.     }
  2048.     if (crc != 0xDEBB20E3L)
  2049.         return ZM_ERROR;
  2050.  
  2051.     return type;
  2052. }
  2053.  
  2054. /*
  2055.  * Receive a data packet ...
  2056.  */
  2057.  
  2058. static int
  2059. zrdat32(buf, length, iprxcount)
  2060. char *buf;
  2061. int length;
  2062. int *iprxcount;
  2063. {
  2064.     int c,d;
  2065.     long crc;
  2066.     char *end;
  2067.  
  2068.     crc = 0xffffffffL;
  2069.     *iprxcount = 0;
  2070.     end = buf + length;
  2071.     while (buf <= end) {
  2072.         if ((c = zdlread ()) & ~0377) {
  2073. crcfoo:
  2074.             switch (c) {
  2075.             case GOTCRCE:
  2076.             case GOTCRCG:
  2077.             case GOTCRCQ:
  2078.             case GOTCRCW:
  2079.             case GOTCRCF:
  2080.                 d = c;
  2081.                 c &= 0377;
  2082.                 crc = UPDC32 (c, crc);
  2083.                 if ((c = zdlread ()) & ~0377)
  2084.                     goto crcfoo;
  2085.                 crc = UPDC32 (c, crc);
  2086.                 if ((c = zdlread ()) & ~0377)
  2087.                     goto crcfoo;
  2088.                 crc = UPDC32 (c, crc);
  2089.                 if ((c = zdlread ()) & ~0377)
  2090.                     goto crcfoo;
  2091.                 crc = UPDC32 (c, crc);
  2092.                 if ((c = zdlread ()) & ~0377)
  2093.                     goto crcfoo;
  2094.                 crc = UPDC32 (c, crc);
  2095.                 if (crc != 0xDEBB20E3L)
  2096.                     return ZM_ERROR;
  2097.                 *iprxcount = length - (end - buf);
  2098.                 return d;
  2099.             case ZM_TIMEOUT:
  2100.             case ZM_RCDO:
  2101.                 return c;
  2102.             default:
  2103.                 return ZM_ERROR;
  2104.             }
  2105.         }
  2106.         *buf++ = (char) c;
  2107.         crc = UPDC32 (c, crc);
  2108.     }
  2109.  
  2110.     return ZM_ERROR;    /* bad packet, too long */
  2111. }
  2112.  
  2113. /*
  2114.  * Respond to receiver's complaint, get back in sync with receiver ...
  2115.  */
  2116.  
  2117. static int
  2118. getinsync(flag)
  2119. boolean flag;
  2120. {
  2121.     int c,cerr;
  2122.     achdrval_t rx_hdr;
  2123.  
  2124.     cerr = cZretries;
  2125.  
  2126.     for (;;) {
  2127.         c = izrecv_hdr (rx_hdr);
  2128.  
  2129.         switch (c) {
  2130.         case ZRPOS:
  2131.             wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos);
  2132.             cZbytes_resent += wpZtxpos - wpZrxpos;
  2133.             wpZlrxpos = wpZtxpos = wpZrxpos;
  2134.             if (wpZlastsync == wpZrxpos) {
  2135.                 if (++iZbeenhereb4 > 4)
  2136.                     if (cZblklen > 32)
  2137.                         cZblklen /= 2;
  2138.                 /* FIXME: shouldn't we reset iZbeenhereb4? */
  2139.             }
  2140.             wpZlastsync = wpZrxpos;
  2141.             return ZRPOS;
  2142.         case ZACK:
  2143.             wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos);
  2144.             wpZlrxpos = wpZrxpos;
  2145.             if (flag || wpZtxpos == wpZrxpos)
  2146.                 return ZACK;
  2147.             break;
  2148.         case ZNAK: {
  2149.             winpos_t rx_bytes;
  2150.             /*
  2151.              * Our partner is in fzfinish_tx() and is waiting
  2152.              * for ZACK ...
  2153.              */
  2154.             zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
  2155.             if (rx_bytes == wpZrxbytes) {
  2156.                 if (!fzsend_hdr (ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), TRUE))
  2157.                     return FALSE;
  2158.             }
  2159.             break;
  2160.         }
  2161.         case ZFIN:
  2162.         case ZM_RCDO:
  2163.             return c;
  2164.         case ZM_TIMEOUT:
  2165.             if (--cerr < 0) {
  2166.                 printmsg (0, "getinsync: retries exhausted");
  2167.                 return ZM_ERROR;
  2168.             }
  2169.             break;    /* sender doesn't send ZNAK for timeout */
  2170.         case ZM_ERROR:
  2171.         default:
  2172.             if (--cerr < 0) {
  2173.                 printmsg (0, "getinsync: retries exhausted");
  2174.                 return ZM_ERROR;
  2175.             }
  2176.             if (!fzsend_hdr (ZHEX, ZNAK, hvzencode_data_hdr (wpZtxpos), TRUE))
  2177.                 return ZM_ERROR;
  2178.             break;
  2179.         }
  2180.     }
  2181. }
  2182.  
  2183. /*
  2184.  * Send a byte as two hex digits ...
  2185.  */
  2186.  
  2187. static char *
  2188. zputhex(p, ch)
  2189. char *p;
  2190. int ch;
  2191. {
  2192.     static char digits[] = "0123456789abcdef";
  2193.  
  2194.     *p++ = digits[(ch & 0xF0) >> 4];
  2195.     *p++ = digits[ch & 0xF];
  2196.     return p;
  2197. }
  2198.  
  2199. /*
  2200.  * Send character c with ZMODEM escape sequence encoding ...
  2201.  *
  2202.  * Escape XON, XOFF.
  2203.  * FIXME: Escape CR following @ (Telenet net escape) ... disabled for now
  2204.  *    Will need to put back references to <lastsent>.
  2205.  */
  2206.  
  2207. static char *
  2208. zputchar(p, ch)
  2209. char *p;
  2210. int ch;
  2211. {
  2212.     char c = ch;
  2213.  
  2214.     /* Quick check for non control characters */
  2215.  
  2216.     if (c & 0140) {
  2217.         *p++ = c;
  2218.     } else {
  2219.         switch (c & 0377) {
  2220.         case ZDLE:
  2221.             *p++ = ZDLE;
  2222.             *p++ = c ^ 0100;
  2223.             break;
  2224.         case CR:
  2225. #if 0
  2226.             if (!fZesc_ctl && (lastsent & 0177) != '@')
  2227.                 goto sendit;
  2228. #endif
  2229.             /* fall through */
  2230.         case 020:    /* ^P */
  2231.         case XON:
  2232.         case XOFF:
  2233.             *p++ = ZDLE;
  2234.             c ^= 0100;
  2235. /*sendit:*/
  2236.             *p++ = c;
  2237.             break;
  2238.         default:
  2239.             if (fZesc_ctl && !(c & 0140)) {
  2240.                 *p++ = ZDLE;
  2241.                 c ^= 0100;
  2242.             }
  2243.             *p++ = c;
  2244.             break;
  2245.         }
  2246.     }
  2247.  
  2248.     return p;
  2249. }
  2250.  
  2251. /*
  2252.  * Decode two lower case hex digits into an 8 bit byte value ...
  2253.  */
  2254.  
  2255. static int
  2256. zgethex()
  2257. {
  2258.     int c,n;
  2259.  
  2260.     if ((c = noxrd7 ()) < 0)
  2261.         return c;
  2262.     n = c - '0';
  2263.     if (n > 9)
  2264.         n -= ('a' - ':');
  2265.     if (n & ~0xF)
  2266.         return ZM_ERROR;
  2267.     if ((c = noxrd7 ()) < 0)
  2268.         return c;
  2269.     c -= '0';
  2270.     if (c > 9)
  2271.         c -= ('a' - ':');
  2272.     if (c & ~0xF)
  2273.         return ZM_ERROR;
  2274.     c += (n << 4);
  2275.  
  2276.     return c;
  2277. }
  2278.  
  2279. /*
  2280.  * Read a byte, checking for ZMODEM escape encoding ...
  2281.  */
  2282.  
  2283. static int
  2284. zdlread()
  2285. {
  2286.     int c;
  2287.  
  2288. again:
  2289.     READCHAR (c, cZtimeout);
  2290.     if (c < 0)
  2291.         return c;
  2292.     if (c & 0140)        /* quick check for non control characters */
  2293.         return c;
  2294.     switch (c) {
  2295.     case ZDLE:
  2296.         break;
  2297.     case XON:
  2298.         goto again;
  2299.     case XOFF:
  2300.         READCHAR (c, XON_WAIT);
  2301.         goto again;
  2302.     default:
  2303.         if (fZesc_ctl && !(c & 0140))
  2304.             goto again;
  2305.         return c;
  2306.     }
  2307.  
  2308. again2:
  2309.     READCHAR (c, cZtimeout);
  2310.     if (c < 0)
  2311.         return c;
  2312.     switch (c) {
  2313.     case ZCRCE:
  2314.     case ZCRCG:
  2315.     case ZCRCQ:
  2316.     case ZCRCW:
  2317.     case ZCRCF:
  2318.         return c | GOTOR;
  2319.     case ZRUB0:            /* FIXME: This is never generated. */
  2320.         return 0177;
  2321.     case ZRUB1:            /* FIXME: This is never generated. */
  2322.         return 0377;
  2323.     case XON:
  2324.         goto again2;
  2325.     case XOFF:
  2326.         READCHAR (c, XON_WAIT);
  2327.         goto again2;
  2328.     default:
  2329.         if (fZesc_ctl && !(c & 0140))
  2330.             goto again2;        /* FIXME: why again2? */
  2331.         if ((c & 0140) == 0100)
  2332.             return c ^ 0100;
  2333.         break;
  2334.     }
  2335.  
  2336.     return ZM_ERROR;
  2337. }
  2338.  
  2339. /*
  2340.  * Read a character from the modem line with timeout ...
  2341.  * Eat parity bit, XON and XOFF characters.
  2342.  */
  2343.  
  2344. static int
  2345. noxrd7()
  2346. {
  2347.     int c;
  2348.  
  2349.     for (;;) {
  2350.         READCHAR (c, cZtimeout);
  2351.         if (c < 0)
  2352.             return c;
  2353.         switch (c &= 0177) {
  2354.         case XON:
  2355.             continue;
  2356.         case XOFF:
  2357.             READCHAR (c, XON_WAIT);
  2358.             continue;
  2359.         case CR:
  2360.         case ZDLE:
  2361.             return c;
  2362.         default:
  2363.             if (fZesc_ctl && !(c & 0140))
  2364.                 continue;
  2365.             return c;
  2366.         }
  2367.     }
  2368. }
  2369.  
  2370. /*
  2371.  * Read a character from the receive buffer, or from the line if empty ...
  2372.  *
  2373.  * <timeout> is in seconds (maybe make it tenths of seconds like in Zmodem?)
  2374.  */
  2375.  
  2376. static int
  2377. realreadchar(timeout)
  2378. int timeout;
  2379. {
  2380. #ifdef THINK_C
  2381.     char c;
  2382.     if (sread(&c, 1, timeout) > 0) {
  2383.         return c;
  2384.     } else {
  2385.         return ZM_TIMEOUT;
  2386.     }
  2387. #else
  2388.     int c;
  2389.     if ((c = breceive_char (timeout, TRUE)) >= 0)
  2390.         return c;
  2391.  
  2392.     switch (c) {
  2393.     case -1:
  2394.         return ZM_TIMEOUT;
  2395.     case -2:
  2396.         return ZM_RCDO;
  2397.     }
  2398. #endif
  2399.  
  2400.     printmsg (0, "realreadchar: breceive_char() returned %d", c);
  2401.     return ZM_ERROR;
  2402. }
  2403.  
  2404. /*
  2405.  * Check if the receive channel has any characters in it.
  2406.  *
  2407.  * At present we can only test the receive buffer. No mechanism is available
  2408.  * to go to the hardware. This should not be a problem though, as long as all
  2409.  * appropriate calls to fsend_data() set <fdoread> to TRUE.
  2410.  */
  2411.  
  2412.  
  2413. static boolean
  2414. fzreceive_ready()
  2415. {
  2416. #ifdef THINK_C
  2417.     return savail() != 0;
  2418. #else
  2419.     return iPrecstart != iPrecend;
  2420. #endif
  2421. }
  2422.  
  2423. /*
  2424.  * Store integer value in an achdrval_t ...
  2425.  */
  2426.  
  2427. static void
  2428. stohdr(val, hdr)
  2429. hdrval_t val;
  2430. achdrval_t hdr;
  2431. {
  2432.     hdr[ZP0] = (char) val;
  2433.     hdr[ZP1] = (char) (val >> 8);
  2434.     hdr[ZP2] = (char) (val >> 16);
  2435.     hdr[ZP3] = (char) (val >> 24);
  2436. }
  2437.  
  2438. /*
  2439.  * Recover an integer from a header ...
  2440.  */
  2441.  
  2442. static hdrval_t
  2443. rclhdr(hdr)
  2444. achdrval_t hdr;
  2445. {
  2446.     hdrval_t v;
  2447.  
  2448.     v = hdr[ZP3] & 0377;
  2449.     v = (v << 8) | (hdr[ZP2] & 0377);
  2450.     v = (v << 8) | (hdr[ZP1] & 0377);
  2451.     v = (v << 8) | (hdr[ZP0] & 0377);
  2452.  
  2453.     return v;
  2454. }
  2455.  
  2456. /*
  2457.  * Encode a <hdrval_t> from the byte count ...
  2458.  *
  2459.  * We use to store the byte count / 32 and a message sequence number which
  2460.  * made this function very useful. Don't remove it.
  2461.  * FIXME: Well, maybe remove it later.
  2462.  */
  2463.  
  2464. static hdrval_t
  2465. hvzencode_data_hdr(cbytes)
  2466. winpos_t cbytes;
  2467. {
  2468.     return (hdrval_t) cbytes;
  2469. }
  2470.  
  2471. /*
  2472.  * Decode a <hdrval_t> into a byte count ...
  2473.  *
  2474.  * We use to store the byte count / 32 and a message sequence number which
  2475.  * made this function very useful. Don't remove it.
  2476.  * FIXME: Well, maybe remove it later.
  2477.  */
  2478.  
  2479. static void
  2480. zdecode_data_hdr(hdrval, pcbytes)
  2481. hdrval_t hdrval;
  2482. winpos_t *pcbytes;
  2483. {
  2484.     *pcbytes = hdrval;
  2485. }
  2486.  
  2487. /*
  2488.  * Update <wpZrxpos> from the received data header value ...
  2489.  *
  2490.  * FIXME: Here is where we'd handle wrapping around at 4 gigabytes.
  2491.  */
  2492.  
  2493. static winpos_t
  2494. lzupdate_rxpos(rx_hdr, rxpos, lrxpos, txpos)
  2495. achdrval_t rx_hdr;
  2496. winpos_t rxpos,lrxpos,txpos;
  2497. {
  2498.     winpos_t rx_pktpos;
  2499.  
  2500.     zdecode_data_hdr (rclhdr (rx_hdr), &rx_pktpos);
  2501.  
  2502.     printmsg (5,
  2503.         "lzupdate_rxpos: rx_pktpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, txpos=0x%lx",
  2504.         rx_pktpos, rxpos, lrxpos, txpos);
  2505.  
  2506.     /*
  2507.      * Check if <rx_pktpos> valid. It could be old.
  2508.      */
  2509.  
  2510.     if (rx_pktpos < wpZlrxpos || rx_pktpos > (wpZtxpos + 1024L & ~1023L))
  2511.         return rxpos;
  2512.  
  2513.     return rx_pktpos;
  2514. }
  2515.